<?php
/**
 * This file houses the Cache class.
 *
 * Copyright (c) 2010, Kalkomey Enterprises, Inc.
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 * - Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright notice, this 
 *   list of conditions and the following disclaimer in the documentation and/or other
 *   materials provided with the distribution.
 * - Neither the name of the Kalkomey Enterprises, Inc. nor the names of its 
 *   contributors may be used to endorse or promote products derived from this 
 *   software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
 * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
 * @copyright Copyright (c) 2010, Kalkomey Enterprises, Inc.
 * @link http://code.google.com/p/swerv
 * @package Framework
 * @subpackage Library
 */

/**
 * The Cache class is used to store key/value pairs in memcache.  Simply by adding a value to a parameter, the value is stored in memcache with that key.  Retrieving the value is as simple as using the parameter again.
 *
 * @package Framework
 * @subpackage Library
 */
class Cache {
	
	/**
	 * Following the Singleton design pattern, this is a single instance of this object.
	 *
	 * @var Cache
	 */
	private static $instance;
	
	/**
	 * A Memcache object (as provided by the memcache pecl extension)
	 *
	 * @var Memcache
	 */
	private $memcache;

	/**
	 * The total number of seconds to keep an item in the cache.  Defaults to zero (no timeout).
	 *
	 * @var integer
	 */
	public $cacheTimeout;

	/**
	 * Object constructor.
	 * Creates a new Memcache object and adds all available servers to the connection pool.
	 *
	 * @uses $memCachePool
	 * 
	 * @throws MemcacheException if Memcache extension does not exist
	 *
	 * @param integer $cacheTimeout the total number of seconds to keep an item in the cache
	 *
	 * @return Cache
	 */
	private function __construct($cacheTimeout = 0) {
		global $memCachePool;
		if (is_array($memCachePool)) {
			if (DISABLE_CACHE === false) {
				if (!class_exists('Memcache')) {
					throw new MemcacheException('Memcache class does not exist.');
				}
				$this->memcache = new Memcache();
				$this->cacheTimeout = $cacheTimeout;
				foreach ($memCachePool as $server) {
					$this->memcache->addServer($server['host'], $server['port'], true, $server['weight']);
				}
			}
		}
	}
	
	/**
	 * Implementation of the Singleton pattern; returns a single instance of this object.
	 *
	 * @param integer $cacheTimeout the total number of seconds to keep an item in the cache
	 *
	 * @return Cache
	 */
	public static function getInstance($cacheTimeout = 0) {
		if (self::$instance != null && self::$instance instanceof Cache) {
			self::$instance->cacheTimeout = $cacheTimeout;
		} else {
			self::$instance = new Cache($cacheTimeout);
		}
		return self::$instance;
	}
	
	/**
	 * Implementation of PHP magic method.
	 * This is called whenever a parameter is asked for that isn't explicitly declared.
	 *
	 * @throws MemcacheException if parameter does not exist in cache
	 *
	 * @param string $paramName the name of the parameter being asked for
	 *
	 * @return mixed
	 */
	public function __get($paramName) {
		if (DISABLE_CACHE === true || ($this->memcache instanceof Memcache) == false) {
			throw new CacheDisabledException('Caching is disabled.');
		}
		$value = $this->memcache->get($paramName);
		if ($value == false) {
			throw new MemcacheException($paramName . ' does not exist in the cache.');
		}
		return $value;
	}
	
	/**
	 * Implementation of PHP magic method.
	 * This is called whenever a parameter is being set that isn't explicitly declared.
	 *
	 * @param string $paramName the name of the parameter being set
	 * @param mixed  $value	 the parameter's new value
	 *
	 * @return void
	 */
	public function __set($paramName, $value) {
		if (DISABLE_CACHE === true || ($this->memcache instanceof Memcache) == false) {
			throw new CacheDisabledException('Caching is disabled.');
		}
		return $this->memcache->set($paramName, $value);
	}
	
	/**
	 * Invalidates all keys in the cache.
	 *
	 * @return bool
	 */
	public function flush() {
		if (DISABLE_CACHE === true || ($this->memcache instanceof Memcache) == false) {
			throw new CacheDisabledException('Caching is disabled.');
		}
		return $this->memcache->flush();
	}
	
	/**
	 * Invalidates a single key in the cache.
	 *
	 * @param string $param the name of the key to invalidate
	 *
	 * @return bool
	 */
	public function delete($param) {
		if (DISABLE_CACHE === true || ($this->memcache instanceof Memcache) == false) {
			throw new CacheDisabledException('Caching is disabled.');
		}
		return $this->memcache->delete($param, 0);
	}
	
}
